/*
 * Copyright (c) 2022, IMMORTA Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * - Neither the name of IMMORTA Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*!
 * @file can_driver.c
 * @brief This file defines can driver functions
 */

/*******Includes***************************************************************/
#include <stdint.h>
#include "can_reg_access.h"

/*******Definitions************************************************************/
#define CAN_MB_HANDLE_PTB       (0U)
#define CAN_MB_HANDLE_STB       (1U)
#define CAN_MB_HANDLE_RXFIFO    (2U)
#define CAN_CTRL0_DEFAULT_VALUE (0x800080)
#define CAN_WAIT_TIME           (1000U)
/*******Variables**************************************************************/
/*! @brief Table to save register base addresses for CAN instances */
static CAN_Type* const s_canRegBase[CONFIG_CAN_INSTANCE_COUNT] = CONFIG_CAN_REG_BASE_PTRS;
/*! @brief Table to save can irq numbers */
static const IRQn_Type s_canIrqId[CONFIG_CAN_INSTANCE_COUNT] = CONFIG_CAN_IRQS;
/*! @brief Table to save can module names */
static const module_names_t s_canModuleName[CONFIG_CAN_INSTANCE_COUNT] = CONFIG_CAN_MODULE_NAMES;
/*! @brief Table to save can clock names */
static const clk_names_t s_canClkName[CONFIG_CAN_INSTANCE_COUNT] = CONFIG_CAN_CLK_NAMES;
static can_state_t* s_canStatePtr[CONFIG_CAN_INSTANCE_COUNT];

/*******Prototypes*************************************************************/
static uint32_t CAN_GetMBHandleIndex(can_buffer_type_t type);
static errcode_t CAN_StartSendData(uint32_t instance,
                                   can_buffer_type_t type,
                                   const can_data_info_t* info,
                                   uint32_t msgId,
                                   const uint8_t* data,
                                   bool isBlocking);

/*******Private Functions******************************************************/

/*******************************************************************************
 *** Function Name : CAN_GetMBHandleIndex
 *** Description   : Return the MB handle index of transmit buffer type
 ******************************************************************************/
static uint32_t CAN_GetMBHandleIndex(can_buffer_type_t type)
{
    uint32_t index = 0U;

    switch (type) {
        case CAN_PRIMARY_TRANSMIT_BUFFER:
            index = CAN_MB_HANDLE_PTB;
            break;

        case CAN_SECONDARY_TRANSMIT_BUFFER:
            index = CAN_MB_HANDLE_STB;
            break;

        case CAN_SECONDARY_SINGLE_TRANSMIT:
            index = CAN_MB_HANDLE_STB;
            break;

        default:
            break;
    }

    return index;
}

/*******************************************************************************
 *** Function Name : CAN_StartSendData
 *** Description   : Send a data frame
 ******************************************************************************/
static errcode_t CAN_StartSendData(uint32_t instance,
                                   can_buffer_type_t type,
                                   const can_data_info_t* info,
                                   uint32_t msgId,
                                   const uint8_t* data,
                                   bool isBlocking)
{
    can_state_t* state = s_canStatePtr[instance];
    CAN_Type* regBase = s_canRegBase[instance];
    uint32_t mb_idx = CAN_GetMBHandleIndex(type);
    errcode_t errCode = ERR_SUCCESS;

    ASSERT_PARAM(state != NULL);

    if (true == state->mbs[mb_idx].isBlocking) {
        errCode = ERR_BUSY;
    } else if ((true == isBlocking) && (state->mbs[mb_idx].state != CAN_MB_IDLE)) {
        errCode = ERR_BUSY;
    } else if (true == CAN_REG_IsTransmitBuffFull(regBase, type)) {
        errCode = ERR_BUSY;
    } else {

    }

    if (errCode == ERR_SUCCESS) {
        state->mbs[mb_idx].state = CAN_MB_TX_BUSY;
        state->mbs[mb_idx].isBlocking = isBlocking;

        CAN_REG_SetTxMsg(regBase, type, info, msgId, data);

        if (type != CAN_SECONDARY_SINGLE_TRANSMIT) {
            CAN_REG_TrigTx(regBase, type, CAN_AMOUNT_TSALL);
        } else {
            CAN_REG_TrigTx(regBase, type, CAN_AMOUNT_TSONE);
        }

    }

    return errCode;
}

/*******************************************************************************
 *** Function Name : CAN_ReadData
 *** Description   : Read a data frame
 ******************************************************************************/
static inline errcode_t CAN_ReadData(uint32_t instance, can_msgbuff_t* data)
{
    CAN_Type* regBase = s_canRegBase[instance];
    errcode_t errCode = ERR_SUCCESS;

    if (0 == CAN_REG_GetRSTAT(regBase)) {
        errCode = ERR_CAN_RXFIFO_EMPTY;
    } else {
        CAN_REG_ReadRxFifo(regBase, data);
    }

    return errCode;
}
/*******Code*******************************************************************/

/*******************************************************************************
 *** Function Name : CAN_GetDefaultConfig
 *** Description   : Get a default can config for user
 ******************************************************************************/
void CAN_GetDefaultConfig(can_config_t* canConfig)
{
    /* Check input parameter */
    ASSERT_PARAM(canConfig != NULL);

    can_time_segment_t timeSeg;

    /* Use default HSE 8M
      Bitrate = HSE / (prescaler + 1) / ((phaseSeg1 + 1) + (phaseSeg2 + 1) + 1)
              = 500K
      Sample point = ((phaseSeg1 + 1) + 1) / ((phaseSeg1 + 1) + (phaseSeg2 + 1) + 1)
                   = 81.25%
    */
    timeSeg.prescaler = 5U;
    timeSeg.phaseSeg1 = 11U;
    timeSeg.phaseSeg2 = 2U;
    timeSeg.rJumpwidth = 2U;
    canConfig->fdEnable = false;
    canConfig->srcClk = CAN_CLK_SRC_HSE;
    canConfig->mode = CAN_NORMAL_MODE;
    canConfig->bitrate = timeSeg;
    canConfig->warnValue = 4U;
}

/*******************************************************************************
 *** Function Name : CAN_Init
 *** Description   : Initialize the CAN peripheral
 ******************************************************************************/
errcode_t CAN_Init(uint32_t instance,
                   can_state_t* state,
                   const can_config_t* canConfig)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);
    ASSERT_PARAM(canConfig != NULL);
    ASSERT_PARAM(state != NULL);
    ASSERT_PARAM(canConfig->warnValue < 6);

    CAN_Type* regBase = s_canRegBase[instance];
    errcode_t errCode = ERR_SUCCESS;
    uint32_t intMask;
    uint32_t timeout = CAN_WAIT_TIME;

    /* Select the CAN function clock source */
    (void)CLOCK_SelectModuleClockSource(s_canClkName[instance], (uint16_t)canConfig->srcClk);
    /* Enable the CAN clock */
    CLOCK_SetModuleBusClockEnable(s_canModuleName[instance], true);
    /* Inactive the CAN peripheral reset */
    CLOCK_SetModuleSoftResetState(s_canModuleName[instance], RESET_INACTIVE);

    while ((CAN_REG_GetCtrl0(regBase) != CAN_CTRL0_DEFAULT_VALUE) && (timeout != 0)) {
        timeout--;
    }

    /* CAN enter Reset mode */
    CAN_REG_SetReset(regBase, true);

    CAN_REG_SetBitrate(regBase, &canConfig->bitrate);

    if (canConfig->fdEnable) {
        CAN_REG_SetBitrateFD(regBase, &canConfig->bitrateFd);
        CAN_REG_SetFdEnable(regBase, true);
    }

    for (uint32_t i = 0U; i < CONFIG_CAN_MAX_MB_NUM; i++) {
        errCode = OS_Adapter_CreateSemaphore(&state->mbs[i].mbSema, 0U);

        if (ERR_SUCCESS != errCode) {
            for (uint32_t j = 0; j < i; j++) {
                (void)OS_Adapter_DestroySemaphore(&state->mbs[j].mbSema);
            }

            errCode = ERR_ERROR;
            break;
        }

        state->mbs[i].isBlocking = false;
        state->mbs[i].state = CAN_MB_IDLE;
    }

    s_canStatePtr[instance] = state;

    state->callback = canConfig->callback;
    state->callbackParam = canConfig->callbackParam;

    CAN_REG_SetReset(regBase, false);

    CAN_REG_SetRom(regBase, CAN_ROM_DISCARD);

    CAN_REG_SetMode(regBase, canConfig->mode);

    CAN_REG_SetBorec(regBase, canConfig->busOffAutoRec);

    CAN_REG_SetInt(regBase, CAN_INT_EN_Msk, false);

    CAN_REG_SetAFWL(regBase,  canConfig->warnValue);

    intMask = (CAN_CTRL1_EIE_Msk | CAN_CTRL1_TSIE_Msk | CAN_CTRL1_TPIE_Msk | CAN_CTRL1_RAFIE_Msk \
               | CAN_CTRL1_RFIE_Msk | CAN_CTRL1_ROIE_Msk | CAN_CTRL1_RIE_Msk);
    CAN_REG_SetInt(regBase, intMask, true);

    NVIC_EnableIRQ(s_canIrqId[instance]);

    OS_Adapter_Init(NULL);

    return errCode;
}
/*******************************************************************************
 *** Function Name : CAN_IrqConfig
 *** Description   : Configure the interrupt enable
 ******************************************************************************/
void CAN_IrqConfig(uint32_t instance, uint32_t mask, bool enable)
{
    CAN_Type* regBase = s_canRegBase[instance];

    CAN_REG_SetInt(regBase, mask, enable);
}

/*******************************************************************************
 *** Function Name : CAN_DeInit
 *** Description   : Close a CAN peripheral
 ******************************************************************************/
void CAN_Deinit(uint32_t instance)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);

    CLOCK_SetModuleSoftResetState(s_canModuleName[instance], RESET_ACTIVE);
    CLOCK_SetModuleBusClockEnable(s_canModuleName[instance], false);
    (void)CLOCK_SelectModuleClockSource(s_canClkName[instance], (uint16_t)CAN_CLK_SRC_OFF);

    if (s_canStatePtr[instance] != NULL) {
        for (uint32_t i = 0; i < CONFIG_CAN_MAX_MB_NUM; i++) {
#ifdef USING_OS_FREERTOS

            if (s_canStatePtr[instance]->mbs[i].mbSema != NULL)
#endif
            {
                (void)OS_Adapter_DestroySemaphore(&s_canStatePtr[instance]->mbs[i].mbSema);
            }
        }
    }

    NVIC_DisableIRQ(s_canIrqId[instance]);

    s_canStatePtr[instance] = NULL;
}

/*******************************************************************************
 *** Function Name : CAN_SetBitrate
 *** Description   : CAN set bit rate for classical CAN
 ******************************************************************************/
void CAN_SetBitrate(uint32_t instance, const can_time_segment_t* bitrate)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);
    ASSERT_PARAM(bitrate != NULL);

    CAN_Type* regBase = s_canRegBase[instance];
    bool resetState = CAN_REG_IsReset(regBase);

    if (resetState == false) {
        CAN_REG_SetReset(regBase, true);
    }

    CAN_REG_SetBitrate(regBase, bitrate);

    if (resetState == false) {
        CAN_REG_SetReset(regBase, false);
    }
}

/*******************************************************************************
 *** Function Name : CAN_GetBitrate
 *** Description   : Get config bitrate
 ******************************************************************************/
void CAN_GetBitrate(uint32_t instance, can_time_segment_t* bitrate)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);
    ASSERT_PARAM(bitrate != NULL);

    CAN_REG_GetBitrate(s_canRegBase[instance], bitrate);
}

/*******************************************************************************
 *** Function Name : CAN_SetBitrate
 *** Description   : CAN set bit rate for CAN FD
 ******************************************************************************/
void CAN_SetBitrateFD(uint32_t instance, const can_time_segment_t* bitrate)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);
    ASSERT_PARAM(bitrate != NULL);

    CAN_Type* regBase = s_canRegBase[instance];
    bool resetState = CAN_REG_IsReset(regBase);

    if (resetState == false) {
        CAN_REG_SetReset(regBase, true);
    }

    CAN_REG_SetBitrateFD(regBase, bitrate);

    if (resetState == false) {
        CAN_REG_SetReset(regBase, false);
    }
}

/*******************************************************************************
 *** Function Name : CAN_GetBitrate
 *** Description   : Get config bitrate
 ******************************************************************************/
void CAN_GetBitrateFD(uint32_t instance, can_time_segment_t* bitrate)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);
    ASSERT_PARAM(bitrate != NULL);

    CAN_REG_GetBitrateFD(s_canRegBase[instance], bitrate);
}

/*******************************************************************************
 *** Function Name : CAN_SetRxFilter
 *** Description   : Set receive filter
 ******************************************************************************/
void CAN_SetRxFilter(uint32_t instance,
                     uint32_t filterNum,
                     const can_filter_config_t* filterTable)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);
    ASSERT_PARAM(filterNum <= CONFIG_CAN_MAX_FILTER_NUM);
    ASSERT_PARAM(filterTable != NULL);

    CAN_Type* regBase = s_canRegBase[instance];
    bool resetState = CAN_REG_IsReset(regBase);

    if (resetState == false) {
        CAN_REG_SetReset(regBase, true);
    }

    CAN_REG_SetRxFilter(regBase, filterNum, filterTable);

    if (resetState == false) {
        CAN_REG_SetReset(regBase, false);
    }
}

/*******************************************************************************
 *** Function Name : CAN_SetTDC
 *** Description   : Set transciver delay compensation
 ******************************************************************************/
void CAN_SetTDCOffset(uint32_t instance, bool enable, uint8_t offset)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);

    CAN_Type* regBase = s_canRegBase[instance];
    bool resetState = CAN_REG_IsReset(regBase);

    if (resetState == false) {
        CAN_REG_SetReset(regBase, true);
    }

    CAN_REG_SetTDCOffset(regBase, enable, offset);

    if (resetState == false) {
        CAN_REG_SetReset(regBase, false);
    }
}

/*******************************************************************************
 *** Function Name : CAN_GetTDCOffset
 *** Description   : Get transciver delay compensation
 ******************************************************************************/
uint8_t CAN_GetTDCOffset(uint32_t instance)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);

    return CAN_REG_GetTDCOffset(s_canRegBase[instance]);
}

/*******************************************************************************
 *** Function Name : CAN_GetTEC
 *** Description   : Get transmit error count
 ******************************************************************************/
uint8_t CAN_GetTEC(uint32_t instance)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);

    return CAN_REG_GetTEC(s_canRegBase[instance]);
}

/*******************************************************************************
 *** Function Name : CAN_GetREC
 *** Description   : Get receive error count
 ******************************************************************************/
uint8_t CAN_GetREC(uint32_t instance)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);

    return CAN_REG_GetREC(s_canRegBase[instance]);
}

/*******************************************************************************
 *** Function Name : CAN_GetErrType
 *** Description   : Get error type
 ******************************************************************************/
can_error_t CAN_GetErrType(uint32_t instance)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);

    can_error_t errType = CAN_ERR_NONE;
    errType = (can_error_t)(CAN_REG_GetKOER(s_canRegBase[instance]));
    return errType;
}

/*******************************************************************************
 *** Function Name : CAN_SendBlocking
 *** Description   : Send a CAN frame use blocking method
 ******************************************************************************/
errcode_t CAN_SendBlocking(uint32_t instance,
                           can_buffer_type_t type,
                           const can_data_info_t* info,
                           uint32_t msgId,
                           const uint8_t* data,
                           uint32_t timeout)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);
    ASSERT_PARAM(info != NULL);
    ASSERT_PARAM(s_canStatePtr[instance] != NULL);

    errcode_t errCode = ERR_SUCCESS;
    can_state_t* state = s_canStatePtr[instance];
    CAN_Type* regBase = s_canRegBase[instance];
    uint32_t mb_idx = CAN_GetMBHandleIndex(type);

    errCode = CAN_StartSendData(instance, type, info, msgId, data, true);

    if (errCode == ERR_SUCCESS) {
        errCode = OS_Adapter_WaitSemaphore(&state->mbs[mb_idx].mbSema, timeout);

        if (errCode == ERR_TIMEOUT) {
            if (state->mbs[mb_idx].state != CAN_MB_IDLE) {
                CAN_REG_AbortTxMsg(regBase, type);
            }
        }

        state->mbs[mb_idx].isBlocking = false;
        state->mbs[mb_idx].state = CAN_MB_IDLE;
    }

    return errCode;
}

/*******************************************************************************
 *** Function Name : CAN_Send
 *** Description   : Send a CAN frame
 ******************************************************************************/
errcode_t CAN_Send(uint32_t instance,
                   can_buffer_type_t type,
                   const can_data_info_t* info,
                   uint32_t msgId,
                   const uint8_t* data)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);
    ASSERT_PARAM(info != NULL);

    return CAN_StartSendData(instance, type, info, msgId, data, false);
}

/*******************************************************************************
 *** Function Name : CAN_ReceiveBlocking
 *** Description   : Receive a CAN frame use blocking method
 ******************************************************************************/
errcode_t CAN_ReceiveBlocking(uint32_t instance,
                              can_msgbuff_t* data,
                              uint32_t timeout_ms)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);
    ASSERT_PARAM(data != NULL);
    ASSERT_PARAM(s_canStatePtr[instance] != NULL);

    errcode_t errCode = ERR_SUCCESS;
    can_state_t* state = s_canStatePtr[instance];

    errCode = CAN_Receive(instance, data);

    if (errCode != ERR_SUCCESS) {
        state->mbs[CAN_MB_HANDLE_RXFIFO].state = CAN_MB_RX_BUSY;
        state->mbs[CAN_MB_HANDLE_RXFIFO].isBlocking = true;
        (void)OS_Adapter_WaitSemaphore(&state->mbs[CAN_MB_HANDLE_RXFIFO].mbSema, timeout_ms);
        errCode = CAN_ReadData(instance, data);
        state->mbs[CAN_MB_HANDLE_RXFIFO].isBlocking = false;
        state->mbs[CAN_MB_HANDLE_RXFIFO].state = CAN_MB_IDLE;
    }

    return errCode;
}

/*******************************************************************************
 *** Function Name : CAN_ReceiveBlocking
 *** Description   : Receive a CAN frame
 ******************************************************************************/
errcode_t CAN_Receive(uint32_t instance, can_msgbuff_t* data)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);
    ASSERT_PARAM(data != NULL);
    ASSERT_PARAM(s_canStatePtr[instance] != NULL);

    can_state_t* state = s_canStatePtr[instance];

    (void)OS_Adapter_WaitSemaphore(&state->mbs[CAN_MB_HANDLE_RXFIFO].mbSema, 0);

    return CAN_ReadData(instance, data);
}

/*******************************************************************************
 *** Function Name : CAN_AbortTransfer
 *** Description   : Abort a transfer
 ******************************************************************************/
void CAN_AbortTransfer(uint32_t instance, can_buffer_type_t type)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);

    CAN_REG_AbortTxMsg(s_canRegBase[instance], type);
}

/*******************************************************************************
 *** Function Name : CAN_GetTransferStatus
 *** Description   : Get transfer status
 ******************************************************************************/
errcode_t CAN_GetTransferStatus(uint8_t instance, can_buffer_type_t type)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);

    CAN_Type* regBase = s_canRegBase[instance];
    errcode_t errCode = ERR_CAN_TX_IDLE;

    if (type == CAN_PRIMARY_TRANSMIT_BUFFER) {
        if (true == CAN_REG_IsTransmitting(regBase, type)) {
            errCode = ERR_CAN_TX_BUSY;
        } else {
            errCode = ERR_CAN_TX_IDLE;
        }
    } else {
        if (true == CAN_REG_IsTransmitBuffFull(regBase, type)) {
            errCode = ERR_CAN_TX_BUSY;
        } else {
            errCode = ERR_CAN_TX_IDLE;
        }
    }

    return errCode;
}

/*******************************************************************************
 *** Function Name : CAN_GetPassiveErrorStatus
 *** Description   : Get passive error status
 ******************************************************************************/
bool CAN_GetPassiveErrorStatus(uint8_t instance)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);

    CAN_Type* regBase = s_canRegBase[instance];

    return CAN_REG_GetPassiveStauts(regBase);
}

/*******************************************************************************
 *** Function Name : CAN_InstallCallback
 *** Description   : Install a callback function
 ******************************************************************************/
void CAN_InstallCallback(uint32_t instance, can_callback_t callback, void* param)
{
    /* Check input parameter */
    ASSERT_PARAM(instance < CONFIG_CAN_INSTANCE_COUNT);
    ASSERT_PARAM(callback != NULL);
    ASSERT_PARAM(s_canStatePtr[instance] != NULL);

    can_state_t* state = s_canStatePtr[instance];

    state->callback = callback;
    state->callbackParam = param;
}

/*******************************************************************************
 *** Function Name : CAN_IRQHandlerProcess / CAN0_IRQHandler
 *** Description   : CAN interrupt handler process
 ******************************************************************************/
/* *INDENT-OFF* */
#if (CONFIG_CAN_IRQ_HANDLER_POS == 1U)
void CAN0_IRQHandler(void)
{
#define regBase CAN0
#define instance 0
    can_state_t* state = s_canStatePtr[0];

#else

void CAN_IRQHandlerProcess(uint32_t instance)
{
    CAN_Type* regBase = s_canRegBase[instance];
    can_state_t* state = s_canStatePtr[instance];
#endif
    uint32_t flag = CAN_REG_GetIntFlag(regBase);
    CAN_REG_ClearIntFlag(regBase, flag);

    if (flag & CAN_CTRL1_RIF_Msk) {

        if (!(flag & CAN_CTRL1_ROIF_Msk)) {
            (void)OS_Adapter_PostSemaphore(&state->mbs[CAN_MB_HANDLE_RXFIFO].mbSema);
        }

        if (state->callback) {
            state->callback(instance, CAN_EVENT_RX_COMPLETE, (void*)state);
        }
    }

    if (flag & CAN_CTRL1_RAFIF_Msk) {
        if (state->callback) {
            state->callback(instance, CAN_EVENT_RX_WARNING, (void*)state);
        }
    }

    if (flag & CAN_CTRL1_RFIF_Msk) {
        if (state->callback) {
            state->callback(instance, CAN_EVENT_RX_FULL, (void*)state);
        }
    }

    if (flag & CAN_CTRL1_ROIF_Msk) {
        if (state->callback) {
            state->callback(instance, CAN_EVENT_RX_OVERFLOW, (void*)state);
        }
    }

    if (flag & CAN_CTRL1_TPIF_Msk) {

        if (state->mbs[CAN_MB_HANDLE_PTB].isBlocking == true) {
            (void)OS_Adapter_PostSemaphore(&state->mbs[CAN_MB_HANDLE_PTB].mbSema);
        }

        state->mbs[CAN_MB_HANDLE_PTB].state = CAN_MB_IDLE;

        if (state->callback) {
            state->callback(instance, CAN_EVENT_PTB_TX_COMPLETE, (void*)state);
        }
    }

    if (flag & CAN_CTRL1_TSIF_Msk) {
        if (true != CAN_REG_IsTransmitBuffEmpty(regBase, CAN_SECONDARY_TRANSMIT_BUFFER)) {
            CAN_REG_TrigTx(regBase, CAN_SECONDARY_TRANSMIT_BUFFER, CAN_AMOUNT_TSONE);
        } else {
            state->mbs[CAN_MB_HANDLE_STB].state = CAN_MB_IDLE;

            if (state->mbs[CAN_MB_HANDLE_STB].isBlocking == true) {
                (void)OS_Adapter_PostSemaphore(&state->mbs[CAN_MB_HANDLE_STB].mbSema);
            }
        }
            if (state->callback) {
                state->callback(instance, CAN_EVENT_STB_TX_COMPLETE, (void*)state);
            }
    }

    if ((flag & CAN_CTRL1_EIF_Msk) && state->callback) {
        if (regBase->CTRL0 & CAN_CTRL0_BUSOFF_Msk) {
            state->callback(instance, CAN_EVENT_BUSOFF, (void*)state);
        } else {
            state->callback(instance, CAN_EVENT_ERR, (void*)state);
        }
    }

    if (flag & CAN_CTRL1_BEIF_Msk) {
        if (state->callback) {
           state->callback(instance, CAN_EVENT_BUS_ERROR, (void*)state);
        }
     }

    if (flag & CAN_CTRL1_AIF_Msk) {
        if (state->callback) {
           state->callback(instance, CAN_EVENT_ABORT, (void*)state);
        }
    }

    if (flag & CAN_CTRL1_ALIF_Msk) {
        if (state->callback) {
           state->callback(instance, CAN_EVENT_ARB_LOST, (void*)state);
        }
    }

    if (flag & CAN_CTRL1_EPIF_Msk) {
        if (state->callback) {
           state->callback(instance, CAN_EVENT_ERR_PASSIVE, (void*)state);
        }
    }

}
/* *INDENT-ON* */

/*******EOF********************************************************************/
